/**
 * AI智能体插件统一错误处理器
 * 提供错误捕获、分类、日志记录、用户提示等功能
 */

import { ERROR_CODES } from '../common/constants.js';
import { getCurrentDateTime, log } from './helpers.js';

/**
 * 错误处理器类
 */
export class ErrorHandler {
  constructor(options = {}) {
    this.options = {
      logLevel: options.logLevel || 'error',
      enableUserToast: options.enableUserToast !== false,
      enableConsoleLog: options.enableConsoleLog !== false,
      maxRetryCount: options.maxRetryCount || 3,
      ...options
    };
    
    // 错误统计
    this.errorStats = {
      total: 0,
      byType: {},
      byCode: {},
      recentErrors: []
    };
    
    // 重试记录
    this.retryCount = {};
  }

  /**
   * 处理错误的主要方法
   * @param {Error|string} error 错误对象或错误消息
   * @param {object} context 错误上下文信息
   * @param {object} options 处理选项
   * @returns {object} 标准化的错误对象
   */
  handle(error, context = {}, options = {}) {
    const standardError = this.standardizeError(error, context);
    
    // 记录错误统计
    this.recordError(standardError);
    
    // 记录日志
    if (this.options.enableConsoleLog) {
      this.logError(standardError);
    }
    
    // 显示用户提示
    if (this.options.enableUserToast && options.showToast !== false) {
      this.showUserToast(standardError, options);
    }
    
    // 触发错误事件
    this.emitErrorEvent(standardError);
    
    return standardError;
  }

  /**
   * 标准化错误对象
   * @param {Error|string} error 原始错误
   * @param {object} context 上下文信息
   * @returns {object} 标准化错误对象
   */
  standardizeError(error, context = {}) {
    let errorCode = ERROR_CODES.API_ERROR;
    let message = '未知错误';
    let originalError = error;
    
    if (typeof error === 'string') {
      message = error;
    } else if (error instanceof Error) {
      message = error.message;
      
      // 根据错误信息判断错误类型
      if (error.message.includes('网络') || error.message.includes('network')) {
        errorCode = ERROR_CODES.NETWORK_ERROR;
      } else if (error.message.includes('WebSocket') || error.message.includes('socket')) {
        errorCode = ERROR_CODES.WEBSOCKET_ERROR;
      } else if (error.message.includes('超时') || error.message.includes('timeout')) {
        errorCode = ERROR_CODES.TIMEOUT_ERROR;
      } else if (error.message.includes('认证') || error.message.includes('token')) {
        errorCode = ERROR_CODES.AUTH_ERROR;
      } else if (error.message.includes('验证') || error.message.includes('validation')) {
        errorCode = ERROR_CODES.VALIDATION_ERROR;
      }
    } else if (error && error.code) {
      errorCode = error.code;
      message = error.message || '未知错误';
    }
    
    return {
      code: errorCode,
      message,
      context,
      originalError,
      timestamp: Date.now(),
      datetime: getCurrentDateTime(),
      stack: originalError instanceof Error ? originalError.stack : null,
      userAgent: this.getUserAgent(),
      url: this.getCurrentUrl()
    };
  }

  /**
   * 记录错误统计信息
   * @param {object} error 标准化错误对象
   */
  recordError(error) {
    this.errorStats.total++;
    
    // 按类型统计
    if (!this.errorStats.byType[error.code]) {
      this.errorStats.byType[error.code] = 0;
    }
    this.errorStats.byType[error.code]++;
    
    // 按错误码统计
    const shortCode = error.code.split('_')[0];
    if (!this.errorStats.byCode[shortCode]) {
      this.errorStats.byCode[shortCode] = 0;
    }
    this.errorStats.byCode[shortCode]++;
    
    // 记录最近错误（保留最近10个）
    this.errorStats.recentErrors.unshift(error);
    if (this.errorStats.recentErrors.length > 10) {
      this.errorStats.recentErrors.pop();
    }
  }

  /**
   * 记录错误日志
   * @param {object} error 标准化错误对象
   */
  logError(error) {
    const logData = {
      code: error.code,
      message: error.message,
      context: error.context,
      timestamp: error.datetime,
      stack: error.stack ? error.stack.split('\n').slice(0, 3) : null
    };
    
    log('error', `[ErrorHandler] ${error.message}`, logData);
  }

  /**
   * 显示用户提示
   * @param {object} error 标准化错误对象
   * @param {object} options 显示选项
   */
  showUserToast(error, options = {}) {
    const userMessage = this.getUserFriendlyMessage(error);
    const toastOptions = {
      title: userMessage,
      icon: 'none',
      duration: options.duration || 3000,
      ...options.toastOptions
    };
    
    try {
      uni.showToast(toastOptions);
    } catch (toastError) {
      console.warn('显示错误提示失败:', toastError);
    }
  }

  /**
   * 获取用户友好的错误消息
   * @param {object} error 标准化错误对象
   * @returns {string} 用户友好的错误消息
   */
  getUserFriendlyMessage(error) {
    const friendlyMessages = {
      [ERROR_CODES.NETWORK_ERROR]: '网络连接异常，请检查网络后重试',
      [ERROR_CODES.WEBSOCKET_ERROR]: '连接异常，正在尝试重连...',
      [ERROR_CODES.API_ERROR]: '服务暂时不可用，请稍后重试',
      [ERROR_CODES.VALIDATION_ERROR]: '输入信息有误，请检查后重试',
      [ERROR_CODES.TIMEOUT_ERROR]: '请求超时，请稍后重试',
      [ERROR_CODES.AUTH_ERROR]: '身份验证失败，请重新登录'
    };
    
    return friendlyMessages[error.code] || error.message || '操作失败，请重试';
  }

  /**
   * 触发错误事件
   * @param {object} error 标准化错误对象
   */
  emitErrorEvent(error) {
    try {
      // 在 uni-app 中可以使用 uni.$emit 触发全局事件
      uni.$emit('ai-agent-error', error);
      
      // 如果有全局错误处理器，调用它
      if (window.globalErrorHandler && typeof window.globalErrorHandler === 'function') {
        window.globalErrorHandler(error);
      }
    } catch (emitError) {
      console.warn('触发错误事件失败:', emitError);
    }
  }

  /**
   * 异步错误处理包装器
   * @param {Function} asyncFunc 异步函数
   * @param {object} context 上下文信息
   * @param {object} options 处理选项
   * @returns {Function} 包装后的函数
   */
  wrap(asyncFunc, context = {}, options = {}) {
    return async (...args) => {
      try {
        return await asyncFunc(...args);
      } catch (error) {
        const handledError = this.handle(error, context, options);
        
        // 如果需要重抛错误
        if (options.rethrow !== false) {
          throw handledError;
        }
        
        return handledError;
      }
    };
  }

  /**
   * 带重试的异步错误处理
   * @param {Function} asyncFunc 异步函数
   * @param {object} retryOptions 重试选项
   * @returns {Function} 包装后的函数
   */
  withRetry(asyncFunc, retryOptions = {}) {
    const {
      maxRetries = this.options.maxRetryCount,
      retryDelay = 1000,
      retryCondition = () => true,
      onRetry = () => {},
      context = {}
    } = retryOptions;
    
    return async (...args) => {
      const functionKey = asyncFunc.name || 'anonymous';
      let lastError;
      
      for (let attempt = 0; attempt <= maxRetries; attempt++) {
        try {
          if (attempt > 0) {
            // 等待重试延迟
            await new Promise(resolve => setTimeout(resolve, retryDelay * attempt));
            onRetry(attempt, lastError);
          }
          
          return await asyncFunc(...args);
        } catch (error) {
          lastError = error;
          
          // 记录重试次数
          if (!this.retryCount[functionKey]) {
            this.retryCount[functionKey] = 0;
          }
          this.retryCount[functionKey]++;
          
          // 检查是否应该重试
          const shouldRetry = attempt < maxRetries && retryCondition(error, attempt);
          
          if (!shouldRetry) {
            break;
          }
          
          log('warn', `[ErrorHandler] 重试 ${functionKey} (${attempt + 1}/${maxRetries + 1})`, {
            error: error.message,
            attempt: attempt + 1
          });
        }
      }
      
      // 所有重试都失败了，处理最终错误
      return this.handle(lastError, {
        ...context,
        function: functionKey,
        totalAttempts: maxRetries + 1,
        finalAttempt: true
      });
    };
  }

  /**
   * 获取错误统计信息
   * @returns {object} 错误统计
   */
  getErrorStats() {
    return {
      ...this.errorStats,
      retryCount: { ...this.retryCount }
    };
  }

  /**
   * 清空错误统计
   */
  clearErrorStats() {
    this.errorStats = {
      total: 0,
      byType: {},
      byCode: {},
      recentErrors: []
    };
    this.retryCount = {};
  }

  /**
   * 获取用户代理信息
   * @returns {string} 用户代理字符串
   */
  getUserAgent() {
    try {
      return navigator.userAgent || 'Unknown';
    } catch {
      return 'Unknown';
    }
  }

  /**
   * 获取当前URL
   * @returns {string} 当前URL
   */
  getCurrentUrl() {
    try {
      return window.location?.href || 'Unknown';
    } catch {
      return 'Unknown';
    }
  }

  /**
   * 创建特定类型的错误处理器
   * @param {string} errorType 错误类型
   * @param {object} defaultContext 默认上下文
   * @returns {Function} 专用错误处理器
   */
  createTypeHandler(errorType, defaultContext = {}) {
    return (error, context = {}, options = {}) => {
      return this.handle(error, {
        type: errorType,
        ...defaultContext,
        ...context
      }, options);
    };
  }
}

/**
 * 默认错误处理器实例
 */
export const defaultErrorHandler = new ErrorHandler();

/**
 * 快捷错误处理方法
 */
export const handleError = (error, context, options) => {
  return defaultErrorHandler.handle(error, context, options);
};

/**
 * 专用错误处理器
 */
export const apiErrorHandler = defaultErrorHandler.createTypeHandler('api');
export const websocketErrorHandler = defaultErrorHandler.createTypeHandler('websocket');
export const validationErrorHandler = defaultErrorHandler.createTypeHandler('validation');
export const networkErrorHandler = defaultErrorHandler.createTypeHandler('network');

/**
 * 错误处理装饰器
 * @param {object} options 装饰器选项
 * @returns {Function} 装饰器函数
 */
export const errorHandler = (options = {}) => {
  return (target, propertyKey, descriptor) => {
    const originalMethod = descriptor.value;
    
    descriptor.value = async function (...args) {
      try {
        return await originalMethod.apply(this, args);
      } catch (error) {
        return defaultErrorHandler.handle(error, {
          method: propertyKey,
          class: target.constructor.name,
          ...options.context
        }, options);
      }
    };
    
    return descriptor;
  };
};

/**
 * 全局错误监听器
 */
export const setupGlobalErrorHandler = () => {
  // 监听未捕获的Promise拒绝
  if (typeof window !== 'undefined') {
    window.addEventListener('unhandledrejection', (event) => {
      defaultErrorHandler.handle(event.reason, {
        type: 'unhandledPromiseRejection',
        promise: event.promise
      });
    });
    
    // 监听全局错误
    window.addEventListener('error', (event) => {
      defaultErrorHandler.handle(event.error || event.message, {
        type: 'globalError',
        filename: event.filename,
        lineno: event.lineno,
        colno: event.colno
      });
    });
  }
  
  // 在uni-app中监听应用级错误
  if (typeof uni !== 'undefined') {
    uni.onError && uni.onError((error) => {
      defaultErrorHandler.handle(error, {
        type: 'uniAppError'
      });
    });
  }
};

export default {
  ErrorHandler,
  defaultErrorHandler,
  handleError,
  apiErrorHandler,
  websocketErrorHandler,
  validationErrorHandler,
  networkErrorHandler,
  errorHandler,
  setupGlobalErrorHandler
}; 